from vnpy.app.cta_strategy import (
    CtaTemplate,
    StopOrder,
    TickData,
    BarData,
    TradeData,
    OrderData,
    BarGenerator,
    ArrayManager,
)


class LSFStrategy(CtaTemplate):
    """"""
    author = "liljay"

    macd_fast_peroid  = 12
    macd_slow_peroid = 26
    single_peroid = 9
    kd_fast_period = 9
    kd_slow_period = 3
    kd_entry = 30
    trailing_percent = 0.1
    # 信号出现之后多少周期内有效
    keep_window = 4
    fixed_size = 10

    # 可买入1， 可做空 -1， 条件不允许0
    big_single = 0
    single_value = 0

    kd_k0 = 0
    kd_k1 = 0

    kd_d0 = 0
    kd_d1 = 0

    kd_long = 0
    kd_short = 0

    intra_trade_high = 0
    intra_trade_low = 0

    parameters = ["macd_fast_peroid", "macd_slow_peroid",
                  "single_peroid", "keep_window", "kd_fast_period", "kd_entry"
                  "kd_slow_period", "trailing_percent", "fixed_size"]


    variables = ["big_single", "single_value","kd_single",
                 "kd_long", "kd_short",
                 "kd_k0",
                 "kd_k1",
                 "kd_d0",
                 "kd_d1",
                 ]

    def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
        """"""
        super(LSFStrategy, self).__init__(
            cta_engine, strategy_name, vt_symbol, setting
        )

        self.kd_long = 50 + self.kd_entry
        self.kd_short = 50 - self.kd_entry

        self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar)
        self.am5 = ArrayManager()

        self.bg15 = BarGenerator(self.on_bar, 15, self.on_15min_bar)
        self.am15 = ArrayManager()

    def on_init(self):
        """
        Callback when strategy is inited.
        """
        self.write_log("策略初始化")
        self.load_bar(1)

    def on_start(self):
        """
        Callback when strategy is started.
        """
        self.write_log("策略启动")

    def on_stop(self):
        """
        Callback when strategy is stopped.
        """
        self.write_log("策略停止")

    def on_tick(self, tick: TickData):
        """
        Callback of new tick data update.
        """
        self.bg5.update_tick(tick)

    def on_bar(self, bar: BarData):
        """
        Callback of new bar data update.
        """
        self.bg5.update_bar(bar)
        self.bg15.update_bar(bar)

    def on_5min_bar(self, bar: BarData):
        """"""
        self.cancel_all()

        self.am5.update_bar(bar)
        if not self.am5.inited:
            return

        if self.big_single == 0:
            return

        small_single = 0
        ks, ds = self.am15.kdj(self.kd_fast_period, self.kd_slow_period, array=True)

        self.kd_k0 = ks[-1]
        self.kd_k1 = ks[-2]

        self.kd_d0 = ds[-1]
        self.kd_d1 = ds[-2]
        
        macd_arr, single_arr, hist_arr = self.am5.macd(self.macd_fast_peroid, self.macd_slow_peroid, self.single_peroid,
                                                        array=True)
        single_value = test_single = single_arr[-1]
        check_arr = single_arr[-self.keep_window: -2].tolist()
        if single_value > 0:
            for i, single in enumerate(check_arr):
                if single < 0:
                    small_single = 0
                    break;
                # 回试0轴
                if test_single > single:
                    test_single = single
                else:
                    small_single = 1
                    break;

        elif single_value < 0:
            for i, single in enumerate(check_arr):
                if single > 0:
                    small_single = 0
                    break;
                # 回试0轴
                if test_single < single:
                    test_single = single
                else:
                    small_single = 1
                    break;
        if self.pos == 0:
            self.intra_trade_high = bar.high_price
            self.intra_trade_low = bar.low_price
            if small_single == 1:
                # 超卖 金叉
                if self.kd_k0 < self.kd_short and self.kd_d0 < self.kd_short and self.kd_k0 > self.kd_d0 and self.kd_k1 < self.kd_d1:
                    self.bug(bar.close_price, self.fixed_size)
            if small_single == -1:
                # 超买 死叉
                if self.kd_k0 > self.kd_long and self.kd_d0 > self.kd_long and self.kd_k0 < self.kd_d0 and self.kd_k1 > self.kd_d1:
                    self.short(bar.close_price, self.fixed_size)
        elif self.pos > 0:
            self.intra_trade_high = max(self.intra_trade_high, bar.high_price)
            self.intra_trade_low = bar.low_price

            long_stop = self.intra_trade_high * \
                        (1 - self.trailing_percent / 100)
            self.sell(long_stop, abs(self.pos), stop=True)
        elif self.pos < 0:
            self.intra_trade_low = min(self.intra_trade_low, bar.low_price)
            self.intra_trade_high = bar.high_price

            short_stop = self.intra_trade_low * \
                         (1 + self.trailing_percent / 100)
            self.cover(short_stop, abs(self.pos), stop=True)


        self.put_event()

    def on_15min_bar(self, bar: BarData):
        """"""
        self.am15.update_bar(bar)
        if not self.am15.inited:
            return
        macd_arr, single_arr, hist_arr = self.am15.macd(self.macd_fast_peroid, self.macd_slow_peroid, self.single_peroid, array=True)
        self.single_value = test_single = single_arr[-1]
        # 检查keep_window窗口数的大周期信号
        check_arr = single_arr[-self.keep_window: -1].tolist()
        check_madc = 0
        if self.single_value > 0:
            for i, single in enumerate(check_arr):
                if single < 0:
                    check_madc = 0
                    break;
                # 回试0轴
                if test_single > single:
                    test_single = single
                else:
                    check_madc = 1
                    break;

        elif self.single_value < 0:
            for i, single in enumerate(check_arr):
                if single > 0:
                    check_madc = 0
                    break;
                # 回试0轴
                if test_single < single:
                    test_single = single
                else:
                    check_madc = 1
                    break;
        k,d = self.am15.kdj(self.kd_fast_period, self.kd_slow_period)
        # 大周期有效窗口检查期内出来金叉，或者死叉就发出大周期信号
        if check_madc == 1:
            if k < self.kd_short and d < self.kd_short:
                self.big_single = 1
            else:
                self.big_single = 0
        elif check_madc == -1:
            if k > self.kd_long and d > self.kd_long:
                self.big_single = -1
            else:
                self.big_single = 0
        else:
            self.big_single = 0

    def on_order(self, order: OrderData):
        """
        Callback of new order data update.
        """
        pass

    def on_trade(self, trade: TradeData):
        """
        Callback of new trade data update.
        """
        print(f"委托ID：{trade.orderid},交易时间：{trade.time},交易方向：{trade.direction.value} {trade.offset.value},交易价格：{trade.price},成交数量：{trade.volume} ")
        self.put_event()

    def on_stop_order(self, stop_order: StopOrder):
        """
        Callback of stop order update.
        """
        pass
